The model reading of the platform: eight bounded contexts, each owning one slice of the business with its own ubiquitous language and its own aggregates, related to its neighbours by explicit context-map patterns. This is design at the level of meaning — what each context is responsible for and where its model ends — not a service or API specification. How the contexts deploy (services, BFFs, the gateway, routes) is the physical view in §8; it follows the model, never the other way round.
Eight contexts partition the business without overlap — every entity in the data model belongs to exactly one. Each has a drill-down developing its language, aggregates, events and the rules that bind it.
| Bounded context | Id | What it is responsible for |
|---|---|---|
| Master — this document | SPEC-DDD | Subdomain map · context map · language & tactical conventions · invariants · physical view |
| Federation | SPEC-DDD-FED | Tenancy · identity & access · the organization-structure model |
| Devices & telemetry | SPEC-DDD-DVC | The device, its telemetry & alerts, the product & schema catalogs |
| Maintenance | SPEC-DDD-MNT | The agreement product, coverage, partner links & the scope resolver |
| Support | SPEC-DDD-SUP | Service tickets & the support conversation |
| Field service | SPEC-DDD-FLD | The on-site visit, runbook, sign-off & maintenance plans |
| Sales | SPEC-DDD-SAL | The contact graph, the funnel & the partner channel |
| Billing | SPEC-DDD-BIL | Billing profiles & the invoice ledger |
| Audit | SPEC-DDD-AUD | The append-only attribution trail |
Not every context deserves equal investment. We classify each by how much it differentiates RiverSync: core domains are the competitive advantage and get the deepest modeling; supporting domains are bespoke but serve the core; generic domains are commodities — candidates to buy or keep deliberately thin.
The product is a monitored, serviced converged micro data center — so Devices, Maintenance and Field service are core. Selling and identity are bespoke but supporting; billing and audit are generic.
Where two contexts meet, the relationship is named with a Domain-Driven Design integration pattern, so the team knows who leads and how models are protected. Upstream contexts produce; downstream contexts adapt. The recurring shapes here:
Each context speaks one precise language — the same words in code, in conversation and in these specs. Two platform-wide conventions keep the languages consistent without flattening them:
The defining terms of each context — Tenant, Device, Maintenance agreement, Contact, Lead, Opportunity, Visit, Invoice — are developed in its drill-down's Ubiquitous language section, rendered from the same catalog.
Inside a context, the model is expressed with a small, consistent vocabulary of building blocks. The conventions every drill-down follows:
| Block | Convention in this model |
|---|---|
| Aggregate | A consistency boundary with one root entity; only the root is referenced from outside, and the aggregate is the unit that enforces its invariants in one transaction. A context owns its aggregates outright (one writer). |
| Entity | Has identity that persists through change (a Device, a Lead). Cross-aggregate references are by identity (an id), never by object graph. |
| Value object | Defined wholly by its attributes, immutable and replaceable — an SLA window, a money amount, a period (PeriodStart…PeriodEnd). No independent identity. |
| Domain event | A past-tense fact a context publishes when something meaningful happened (aggregate.fact). Events are the published language between contexts; Audit consumes them all. |
| Domain service / policy | Behaviour that doesn't belong to a single entity — the partner-scope resolver, the won-deal provisioning saga, the channel-allocation policy. Stateless, named in the language. |
| Repository | Persists and reconstitutes an aggregate by its root; the boundary at which a cross-context reference degrades to a validated identifier. |
The rules that keep the model honest — boundaries, integration and consistency. Defined once in the central catalog; each drill-down repeats the subset that binds it. Sources cited per rule; the requirement IDs join the master ERD's traceability discipline.
Identity is upstream of everything. Federation issues the federated token at sign-in; every context conforms to its claims (TenantId, tenant type, the per-app role map) and re-derives no identity of its own. The fine-grained permission is applied by the owning context. (SVC-4, SVC-5)
Tenant context travels with the work. The verified TenantId flows from the edge through every call and into each event envelope; a context scopes its rows by it and never trusts a client-supplied tenant id. RiverSync cross-tenant access is explicit — a riversync role or an audited view-as session. (SVC-4, DM-20)
Every change is a fact, and Audit hears them all. A state change emits its domain event; Audit subscribes to the whole backbone and projects the per-tenant trail with attribution preserved. Audit is a consumer, never a dependency — no context waits on it. (SVC-8)
Telemetry is a separate plane. Devices ingest over mTLS straight into the Devices context, into a time-series store outside Postgres; only Alert rows cross into the relational model — the same ⚠ boundary the ERD records under PTL-1. (SVC-9)
The deployment mapping, kept distinct from the model above. Each bounded context becomes one domain service (its own store, the only writer of its aggregates); the six apps compose through a backend-for-frontend behind one gateway; contexts integrate over an event backbone. This is one valid mapping of the model — not the model itself.
Service catalog. One service per context, the owned aggregates and the route surface each exposes:
Which app composes which context. An app's BFF reads a fixed set of contexts; everything else it appears to know arrives via events and projections. Partner-tenant reads always pass the Maintenance scope resolver first (SVC-6).
API & event conventions (physical): routes are relative to api.riversync.com/v1 with a per-context prefix; resources plural & kebab-case, payload attributes PascalCase; events named aggregate.fact, past-tense, at-least-once, ordered per aggregate. The full endpoint catalog lives in each context's drill-down.
Every context's published events in one place — the shared language the whole platform integrates through. Each drill-down renders its own slice.
Each context traces to the PRD set and the ERD it models; the invariants cite their sources inline. Gaps are flagged ⚠ in the same discipline as the master ERD.
| Context | Requirements | Data model |
|---|---|---|
| Federation | TEN-1…3 · ID-1…4 · AUTH-1…7 · ACC-1 · ACC-2 · ACC-5 · ADM-1…3 · PRT-3 | DM-1…11 · SPEC-ERD-ACC · SPEC-ERD-ADM |
| Devices & telemetry | PTL-1…3 · PTL-5 · ADM-2 · PRO-1…6 | DM-18 · DM-35–38 · SPEC-ERD-PTL · SPEC-ERD-PRO |
| Maintenance | PRT-1…8 · PAR-1 · PAR-8 | DM-12…17 · SPEC-ERD-PAR |
| Support | PTL-2 · PTL-4 · PAR-2 | DM-19 · SPEC-ERD-PTL |
| Field service | FLD-1…10 · DM-11 | DM-27…31 · SPEC-ERD-FLD |
| Sales | SAL-1…8 · PIP-1…8 · PAR-6…7 · PRT-9…17 | DM-22…25 · DM-39…52 · SPEC-ERD-PIP · SPEC-ERD-PAR |
| Billing | ACC-3 · ADM-3 | DM-21 · SPEC-ERD-ACC |
| Audit | PRT-4 · ADM-5 | DM-20 · SPEC-ERD-ADM |
| Version | Date | Changes |
|---|---|---|
| 0.10–0.13 | Jun 2026 | Prior architecture line — the seven/eight-service split, Agreement→Maintenance rename + channel-to-Sales move, FK naming, Devices product/schema ownership, and the "Domain & services → Domain-Driven Design" family rename (which recoded ids but, as logged, made no model change). |
| 0.14 | 28 Jun 2026 | Reframed as actual Domain-Driven Design. The set now leads with the model, not the back-end: bounded contexts (§1), a subdomain classification — core · supporting · generic (§2), an explicit context map naming the integration pattern on every relationship — ACL, open-host/published-language, conformist, customer/supplier, partnership (§3), platform ubiquitous-language conventions (§4) and the tactical building blocks — aggregates, entities, value objects, domain events, domain services/policies (§5). The SVC-rules are reframed as domain invariants & modeling rules (§6); the service split, BFF/gateway and API/event conventions are demoted to an explicit physical view (§8) that maps the model to deployment. Tactical detail (per-context ubiquitous language + aggregates) is added once to domain-catalog.js and rendered across the set; Sales is the fully-worked exemplar. App references use the canonical DS surface pills. No requirement or entity-ownership change — a presentation & modeling-rigor change. |
| 0.15 | 28 Jun 2026 | Sales gains the communications inbox (SPEC-PRD SAL-9). Sales now owns Conversation and Message — the unified multi-channel inbox (web-form · email · LINE · Instagram · Facebook · LinkedIn · phone), anchored to a Contact and foldered. New domain events message.received · message.sent · conversation.foldered; new /sales/conversations routes; the Conversation aggregate (root + Message) added to Sales tactical detail. SVC-18 extended — distinct from Support's ChatThread; every message also writes an Activity. Cascaded from SPEC-PRD v0.34 / SPEC-ERD v0.25 (DM-53/54) / SPEC-APP-PIP v0.8. Catalog-driven (domain-catalog.js · domain-routes.js). |